#pragma once

#include "../comm/log.hpp"
#include "../comm/util.hpp"

#include <iostream>
#include <string>
#include <vector>
#include <cassert>
#include <unordered_map>
#include <fstream>
#include <cstdlib>

//根据题目list文件，加载所有的题目信息到内存中
//model：主要用来和数据进行交互，对外提供访问数据的接口

namespace ns_model
{
    using namespace std;
    using namespace ns_log;
    using namespace ns_util;

    struct Question{
        string number;//题号
        string title;//题目标题
        string star;//难度
        int cpu_limit;//时间限制
        int mem_limit;//空间限制
        string desc;//题目描述
        string header;//给用户的预设代码
        string tail;//测试用例，和预设代码结合形成完整代码
    };

    const std::string questions_list = "./questions/questions.list";
    const std::string question_path = "./questions/";

    class Model{
        private:
            unordered_map<string, Question> questions;
        public:
            Model()
            {
                assert(LoadQuestionList(questions_list));
            }
            bool LoadQuestionList(const string& question_list)
            {
                //加载配置文件：questions/question.list + 题目编号文件
                ifstream in(question_list);
                if(!in.is_open())
                {
                    LOG(FATAL) << "加载题库失败，请检查是否存在题库文件" << "\n";
                    return false;
                }

                string line;
                while(getline(in, line))
                {
                    vector<string> tokens;
                    StringUtil::SplitString(line, &tokens, " ");
                    //cout << tokens.size() << endl;        0?
                    if(tokens.size() != 5)
                    {
                        LOG(WARNING) <<"加载部分题目失败，请检查文件格式" << "\n";
                        continue;
                    }
                    //1 判断回文数 简单 1 30000
                    Question q;
                    q.number = tokens[0];
                    q.title = tokens[1];
                    q.star = tokens[2];
                    q.cpu_limit = atoi(tokens[3].c_str());
                    q.mem_limit = atoi(tokens[4].c_str());
                    string path = question_path;
                    path += q.number;
                    path += "/";
                    FileUtil::ReadFile(path+"desc.txt", &(q.desc), true);
                    FileUtil::ReadFile(path+"header.cpp", &(q.header), true);
                    FileUtil::ReadFile(path+"tail.cpp", &(q.tail), true);

                    questions.insert({q.number, q});
                }

                LOG(INFO) << "加载题库...成功！" << "\n";
                in.close();
                return true;
            }
            bool GetAllQuestions(vector<Question>* out)
            {
                if(questions.size() == 0)
                {
                    LOG(ERROR) << "用户获取题库失败" << "\n";
                    return false;
                }
                for(const auto& q : questions)
                {
                    out->push_back(q.second);
                }
                return true;
            }
            bool GetOneQuestion(const string& number, Question *q)
            {
                const auto& iter = questions.find(number);
                if(iter == questions.end())
                {
                    LOG(ERROR) << "用户获取题目失败， 题目编号" << number << "\n";
                    return false;
                }
                (*q) = iter->second;
                return true;
            }
            ~Model() {}

    };
}